package com.ocm.tourism.web;

import java.awt.Dimension;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.util.UriUtils;
import org.springframework.web.util.WebUtils;

import com.ocm.tourism.core.domain.Business;
import com.ocm.tourism.core.domain.BusinessType;
import com.ocm.tourism.core.domain.CommonItems;
import com.ocm.tourism.core.domain.CulinaryCulture;
import com.ocm.tourism.core.domain.Distance;
import com.ocm.tourism.core.domain.FileInfo;
import com.ocm.tourism.core.service.BusinessService;
import com.ocm.tourism.core.service.CataloguesService;
import com.ocm.tourism.core.service.CommonItemsService;
import com.ocm.tourism.core.user.BusinessServiceClient;
import com.ocm.tourism.core.util.TourismUtil;
import com.ocm.tourism.file.MimeTypeSupport;
import com.ocm.tourism.file.SimpleImageInfo;
import com.ocm.tourism.web.util.FileInfoUtil;

@RequestMapping("/restaurant")
@Controller
public class RestaurantController {

   @Autowired
   CataloguesService cataloguesService;

   @Autowired
   BusinessService businessService;

   @Autowired
   BusinessServiceClient businessServiceClient;

   @Autowired
   CommonItemsService commonItemsService;

   @Autowired
   FileInfoUtil fileInfoUtil;

   @InitBinder
   public void initBinder(WebDataBinder binder) {
        binder.initDirectFieldAccess();
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }

   @RequestMapping(value = "/create", method = RequestMethod.GET)
   public String createForm(Model uiModel) {
      Business business = new Business();
      business.setBusinessType(BusinessType.RESTAURANT);
      populateEditForm(uiModel, business);
      return "restaurant/create";
   }

   @RequestMapping(value = "/{id}", method=RequestMethod.GET)
   public String show(@PathVariable("id") Long id, Model uiModel) {
      uiModel.addAttribute("itemId", id);
      return "restaurant/show";
   }

   @RequestMapping(value = "/{id}/info", method=RequestMethod.GET)
   public String showInfo(@PathVariable("id") Long id, Model uiModel) {
      this.businessServiceClient.validatedAcceptBusiness(id);
      uiModel.addAttribute("itemId", id);
      Business business = this.businessService.findBusiness(id);
      populateEditForm(uiModel, business);
      return "restaurant/info";
   }
   
   @RequestMapping(value = "/{id}/detail", method=RequestMethod.GET)
   public String showDetail(@PathVariable("id") Long id, Model uiModel) {
      uiModel.addAttribute("itemId", id);
      CulinaryCulture business = this.businessService.findCulinary(id);
      uiModel.addAttribute("restaurant", business);
      uiModel.addAttribute("distances", business.getDistances());
      return "restaurant/detail";
   }

   @RequestMapping(value = "/{id}/update", method=RequestMethod.GET)
   public String showUpdate(@PathVariable("id") Long id, Model uiModel) {
      uiModel.addAttribute("itemId", id);
      uiModel.addAttribute("selected", "info");
      uiModel.addAttribute("selectedUrl", "/restaurant/"+id+"/update/form");
      return "restaurant/show";
   }
   
   @RequestMapping(value = "/{id}/update/form", method=RequestMethod.GET)
   public String showUpdateForm(@PathVariable("id") Long id, Model uiModel) {
      this.businessServiceClient.validatedAcceptBusiness(id);
      uiModel.addAttribute("itemId", id);
      Business business = this.businessService.findBusiness(id);
      populateEditForm(uiModel, business);
      return "restaurant/update";
   }

   @RequestMapping(value = "/{id}/menu", method=RequestMethod.GET)
   public String showOrderMenu(@PathVariable("id") Long id, Model uiModel) {
      this.businessServiceClient.validatedAcceptBusiness(id);
      uiModel.addAttribute("itemId", id);
      Business business = this.businessService.findCulinary(id);
      uiModel.addAttribute("restaurant", business);
      return "restaurant/ordermenu/show";
   }

   @RequestMapping(value = "/{id}/menu/show", method=RequestMethod.GET)
   public String showOrderMenuView(@PathVariable("id") Long id, Model uiModel) {
      uiModel.addAttribute("itemId", id);
      uiModel.addAttribute("selected", "menu");
      uiModel.addAttribute("selectedUrl", "/restaurant/"+id+"/menu");
      return "restaurant/show";
   }

   @RequestMapping(value = "/{id}/menu/update", method=RequestMethod.GET)
   public String showOrderMenuUpdate(@PathVariable("id") Long id, Model uiModel) {
      uiModel.addAttribute("itemId", id);
      uiModel.addAttribute("selected", "menu");
      uiModel.addAttribute("selectedUrl", "/restaurant/"+id+"/menu/update/form");
      return "restaurant/show";
   }

   @RequestMapping(value = "/{id}/menu/update/form", method=RequestMethod.GET)
   public String showOrderMenuViewForm(@PathVariable("id") Long id, Model uiModel) {
      this.businessServiceClient.validatedAcceptBusiness(id);
      uiModel.addAttribute("itemId", id);
      Business business = this.businessService.findCulinary(id);
      uiModel.addAttribute("restaurant", business);
      return "restaurant/ordermenu/update";
   }

   @RequestMapping(value = "/{id}/files",produces = "text/html", method=RequestMethod.GET)
   public String viewFiles(@PathVariable("id")Long retaurantId, Model uiModel) {
      uiModel.addAttribute("itemId", retaurantId);
      uiModel.addAttribute("selected", "file");
      uiModel.addAttribute("selectedUrl", "/fileInfo/business/"+retaurantId+"/restaurant");
      return "hotel/show";
   }

   @RequestMapping(value = "/{id}/file/create",produces = "text/html", method=RequestMethod.GET)
   public String viewCreate(@PathVariable("id")Long retaurantId, Model uiModel) {
      uiModel.addAttribute("itemId", retaurantId);
      uiModel.addAttribute("selected", "file");
      uiModel.addAttribute("selectedUrl", "/fileInfo/business/"+retaurantId+"/restaurant/create");
      return "hotel/show";
   }

   @RequestMapping(value="/ordermenu", method = RequestMethod.PUT)
   public String updateRoom(CulinaryCulture culinaryCulture, BindingResult bindingResult, Model uiModel) {
      this.businessServiceClient.validatedAcceptBusiness(culinaryCulture.getId());
      CulinaryCulture actual = this.businessService.findCulinary(culinaryCulture.getId());
      actual.setContent(culinaryCulture.getContent());
      uiModel.asMap().clear();
      this.businessService.saveBusiness(actual);
      return "redirect:/restaurant/"+culinaryCulture.getId()+"/menu/show";
   }

   @RequestMapping(method = RequestMethod.POST)
   public String create(@Valid CulinaryCulture business, @RequestParam("fileData")CommonsMultipartFile commonsMultipartFile, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
      validate(commonsMultipartFile, uiModel, bindingResult);
      if (bindingResult.hasErrors()) {
         populateEditForm(uiModel, business);
         return "restaurant/create";
      }
      if (commonsMultipartFile.getSize() > 0){
         String uploadDir = httpServletRequest.getSession().getServletContext().getInitParameter("uploadDir");
         String folderPath = fileInfoUtil.createContainer(uploadDir);
         FileInfo fileInfo = fileInfoUtil.writeFile(commonsMultipartFile, uploadDir, folderPath);
         business.setAvatar(fileInfo);
      }
      uiModel.asMap().clear();
      this.businessService.saveBusiness(business);
      return "redirect:/restaurant?page=1&size=50";
   }
   
   @RequestMapping(value="/update", method = RequestMethod.POST)
   public String update(@Valid CulinaryCulture business, @RequestParam("fileData")CommonsMultipartFile commonsMultipartFile, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) throws Exception {
      this.businessServiceClient.validatedAcceptBusiness(business.getId());
      validate(commonsMultipartFile, uiModel, bindingResult);
      if (bindingResult.hasErrors()) {
         populateEditForm(uiModel, business);
         return "restaurant/create";
      }
      Business actual = this.businessService.findBusiness(business.getId());
      if (commonsMultipartFile.getSize() > 0){
         String uploadDir = httpServletRequest.getSession().getServletContext().getInitParameter("uploadDir");
         String folderPath = fileInfoUtil.createContainer(uploadDir);
         FileInfo fileInfo = fileInfoUtil.writeFile(commonsMultipartFile, uploadDir, folderPath);
         business.setAvatar(fileInfo);
      }else{
         business.setAvatar(actual.getAvatar());
      }
      uiModel.asMap().clear();
      business.setParticipant(actual.getParticipant());
      businessService.saveBusiness(business);
      return "redirect:/restaurant/" + encodeUrlPathSegment(business.getId().toString(), httpServletRequest);
   }
   
   @RequestMapping(produces = "text/html", method=RequestMethod.GET)
   public String list(@RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size, Model uiModel) {
      long count = businessServiceClient.countRestaurants();
       if (page != null || size != null) {
           int sizeNo = size == null ? 10 : size.intValue();
           final int firstResult = page == null ? 0 : (page.intValue() - 1) * sizeNo;
           uiModel.addAttribute("businesses", businessServiceClient.findRestaurants(firstResult, sizeNo));
           float nrOfPages = count / sizeNo;
           uiModel.addAttribute("maxPages", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1 : nrOfPages));
       } else {
           List<CulinaryCulture> culinaryCultures =  count == 0 ? new ArrayList<CulinaryCulture>() : businessServiceClient.findRestaurants(0, 25);
           uiModel.addAttribute("businesses", culinaryCultures);
       }
       return "restaurant/list";
   }

   @RequestMapping(value="/advs", produces = "text/html", method=RequestMethod.GET)
   public String listAdvs(@RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size, Model uiModel) {
       long count = businessService.countRestaurants();
       page = page == null ? 1 : page; 
       int sizeNo = size == null ? 25 : size.intValue();
       final int firstResult = page == null ? 0 : (page.intValue() - 1) * sizeNo;
       uiModel.addAttribute("businesses", businessService.findRestaurantAdvs(firstResult, sizeNo));
       float nrOfPages = (float)  count/ sizeNo;
       int maxPages = (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1 : nrOfPages);
       uiModel.addAttribute("maxPages", maxPages);
       uiModel.addAttribute("nextPage", TourismUtil.getNextPage(page, maxPages));
       uiModel.addAttribute("submenuSelected", "resteraunt");
       return "restaurant/advs";
   }

   @RequestMapping(value = "/{id}/distance/update", method = RequestMethod.GET)
   public String infoUpdateDistances(@PathVariable("id")Long businessId, Model uiModel) {
      uiModel.addAttribute("itemId", businessId);
      uiModel.addAttribute("selected", "distance");
      uiModel.addAttribute("selectedUrl", "/distance/restaurant/"+businessId+"/update/form");
      return "restaurant/show";
   }

   @RequestMapping(value = "/{id}/distance",produces = "text/html", method=RequestMethod.GET)
   public String viewDistances(@PathVariable("id")Long businessId, Model uiModel) {
      this.businessServiceClient.validatedAcceptBusiness(businessId);
      List<Distance> distances = businessService.findDistancesByCalinary(businessId);
      uiModel.addAttribute("distances", distances);
      uiModel.addAttribute("businessId", businessId);
      uiModel.addAttribute("businessType", "restaurant");
      return "distance/show";
   }

   @RequestMapping(value = "/{id}/distance/list",produces = "text/html", method=RequestMethod.GET)
   public String viewDistancesList(@PathVariable("id")Long businessId, Model uiModel) {
      uiModel.addAttribute("itemId", businessId);
      uiModel.addAttribute("selected", "distance");
      uiModel.addAttribute("selectedUrl", "/restaurant/"+businessId+"/distance");
      return "restaurant/show";
   }

   void populateEditForm(Model uiModel, Business business) {
      uiModel.addAttribute("business", business);
      List<CommonItems> countries = commonItemsService.findAllCountrys();
      countries.add(0, new CommonItems());
      uiModel.addAttribute("countries", countries);
      uiModel.addAttribute("cities", commonItemsService.findAllCitys());
   }

   void validate(CommonsMultipartFile commonsMultipartFile,Model uiModel, Errors errors) throws IOException{
      if (commonsMultipartFile.getSize() > 0){
         InputStream inputStream = commonsMultipartFile.getInputStream();
         if (!MimeTypeSupport.supportMineType(commonsMultipartFile.getContentType())){
            errors.reject("error_fileData_contenttype");
         }
         if (commonsMultipartFile.getSize() > FileInfoUtil.DEFAULT_BUFFER_SIZE){
            errors.reject("error_fileData_large");
         }
         if (!errors.hasFieldErrors("fileData")){
            Dimension dimension = SimpleImageInfo.processStream(inputStream);
            if (dimension.getWidth() < 200){
               errors.reject("error_fileData_limit_width");
            }
         }
      }
   }
   
   String encodeUrlPathSegment(String pathSegment, HttpServletRequest httpServletRequest) {
      String enc = httpServletRequest.getCharacterEncoding();
      if (enc == null) {
          enc = WebUtils.DEFAULT_CHARACTER_ENCODING;
      }
      try {
          pathSegment = UriUtils.encodePathSegment(pathSegment, enc);
      } catch (UnsupportedEncodingException uee) {}
      return pathSegment;
  }
}
